<?php
require_once 'Simpple/Controller/Request.php';
require_once 'Simpple/Controller/Router.php';
class Simpple_Dispatcher {
	private static $dispatcher;
	/**
	 * @var Simpple_Controller_Request
	 */
	private $request;
	/**
	 * @var Simpple_Controller_Router
	 */
	private $router;
	/**
	 * 控制器重定向器
	 *
	 * @var function
	 */
	private $errorController = 'ErrorController';
	
	/**
	 * 获取分配器
	 *
	 * @return Simpple_Dispatcher
	 */
	public static function getInstance() {
		if (!self::$dispatcher) {
			self::$dispatcher = new Simpple_Dispatcher();
		}
		return self::$dispatcher;
	}
	
	/**
	 * 初始化请求
	 *
	 * @param Simpple_Controller_Request $request
	 */
	public function initRequest($request=null) {
		if ($request instanceof Simpple_Controller_Request) {
			$this->request = $request;
			return;
		}
		$req = new Simpple_Controller_Request();
		$this->request = $req;
	}
	
	/**
	 * 初始化路由器
	 *
	 * @param Simpple_Controller_Router $router
	 */
	public function initRouter($router=null) {
		if ($router instanceof Simpple_Controller_Router){
			$this->router = $router;
			return;
		}
		$this->router = new Simpple_Controller_Router();
	}
	
	
	/**
	 * 获取准备好的请求
	 *
	 * @param $modules array
	 * @return Simpple_Controller_Request
	 */
	private function getPreparedRequest($modules = null) {
		if (!$this->request){
			$this->initRequest();
			
			if (!$this->router) {
				$this->initRouter();
			}
			$this->router->setModules($modules);
			$keys = $this->router->getParamsFromUrl();
			$this->request->initKeys($keys);
			
			$this->request->initParams($_REQUEST);
		}
		return $this->request;
	}
	
	/**
	 * 更改错误控制器名称，当找不到控制器时会将控制权交给他的errorAction处理
	 *
	 * @param string $callback
	 */
	public function setErrorController($controllerName) {
		$this->errorController = $controllerName;
	}
	
	/**
	 * 处理控制器的方法
	 *
	 * @param string $path 控制器路径
	 */
	public function handler($path) {
		if (!$path) {
			throw new Simpple_Exception("the path is not defined");
		}
		if (!is_array($path)) {
			$req = $this->getPreparedRequest();
		} else {
			$req = $this->getPreparedRequest(array_keys($path));
			$module = $req->getModuleName();
			if (!isset($path[$module])) {
				throw new Simpple_Exception("the path of module({$module}) is not defined");
			}
			$path = $path[$module];
		}
		set_include_path(get_include_path()
			.PATH_SEPARATOR.$path.'/controllers'
			.PATH_SEPARATOR.$path.'/models'
		);
		
		$controller = $req->getControllerName();
		$action = $req->getActionName();
		
		$ctlName = ucfirst($controller).'Controller';
		$actionName =  ucfirst($action);
		$actionName = strtolower(substr($actionName, 0, 1)).substr($actionName, 1)."Action";
		
		if (!class_exists($ctlName)) {
			if ($this->errorController) {
				$newClass = ucfirst($this->errorController).'Controller';
				if (class_exists($newClass))
				{
					$req = $req->copy();
					$req->setControllerName($ctlName);
					
					$ctl = new $newClass();
				} else {
					throw new Exception("can't load the error Controller {$newClass}");
				}
				
				if (!method_exists($ctl, $actionName)) {
					throw new Exception("cann't find {$actionName} in {$ctlName}");
				}
			} else {
				throw new Exception("can't load the controller {$ctlName}");
			}
		} else {
			$ctl = new $ctlName();
		}
		require_once 'Simpple/Controller/Abstract.php';
		if ($ctlName instanceof Simpple_Controller_Abstract) {
			throw new Exception("the class {$ctlName} must be a instance of Simpple_Controller_Abstract");
		}
		
		$ctl->setRequest($req);
		
		if (!method_exists($ctl, $actionName)) {
			throw new Exception("cann't find {$actionName} in {$ctlName}");
		}
		
		$ctl->initView($path);
		try {
			$ctl->init();
			call_user_func(array($ctl, $actionName),null);
		} catch(Exception $ex) {
			if (class_exists('Simpple_Logger', false)) {
				Simpple_Logger::close();
			}
			$ctl->__error($ex);
		}
	}
	
}